package com.fyx.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fyx.config.FiveMongoConfig;
import com.fyx.entity.*;
import com.fyx.mapper.*;
import com.fyx.service.IChannelService;
import com.fyx.until.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.SkipOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.security.spec.X509EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.interfaces.RSAPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.*;
import java.io.ByteArrayOutputStream;
import javax.annotation.Resource;
import javax.crypto.Cipher;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.sql.Array;
import java.sql.Timestamp;
import java.util.*;

import static org.springframework.data.mongodb.core.aggregation.Aggregation.match;

@Service
public class ChannelServiceImpl extends ServiceImpl<SysDictDetailMapper, SysDictDetail>  implements IChannelService {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Resource(name = FiveMongoConfig.MONGO_TEMPLATE)
    private MongoTemplate fiveMongoTemplate;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private ChannelLtvMapper channelLtvMapper;

    @Autowired
    private ChannelIdDataMapper channelIdDataMapper;

    @Override
    public Map channelUser(UserEntity userEntity, Pageable pageable) {
        Query query = new Query();
        query.skip((pageable.getPageNumber())*pageable.getPageSize());
        query.limit(pageable.getPageSize());
        Criteria criteria = new Criteria();

        if(!CollectionUtils.isEmpty(userEntity.getDeptIds())){
            List<Long> deptIds= new ArrayList<>(userEntity.getDeptIds());
            List<SysUser> channels = sysUserMapper.getUserNames(deptIds);
            String channel[] = new String[channels.size()];

            for(int i=0; i<channels.size();i++){
                channel[i]=channels.get(i).getUsername();
            }

            criteria.and("channel").in(channel);
        }

        if (StringUtils.isNotBlank(userEntity.getUserid())){
            criteria.and("userid").is(userEntity.getUserid());
        }

        if (userEntity.getQregTime()!=null){
            criteria.andOperator(Criteria.where("reg_time").gte(userEntity.getQregTime().get(0).getTime()/1000).lte(userEntity.getQregTime().get(1).getTime()/1000));
        }else{
            criteria.andOperator(Criteria.where("reg_time").gte(DateUtil.getDayBegin().getTime()/1000).lte(DateUtil.getDayEnd().getTime()/1000));
        }
        query.addCriteria(criteria);
        query.with(Sort.by(Sort.Direction.DESC,new String[]{"reg_time"}));
        List<UserEntity> list = mongoTemplate.find(query, UserEntity.class);
        long total = mongoTemplate.count(query, UserEntity.class);

        Map map =new HashMap();
        map.put("list",list);
        map.put("total",total);
        return map;
    }

    @Override
    public Map channelRecharge(OrderEntity orderEntity, Pageable pageable) {
        Criteria criteria = new Criteria();
        if(!CollectionUtils.isEmpty(orderEntity.getDeptIds())){
            List<Long> deptIds= new ArrayList<>(orderEntity.getDeptIds());
            List<SysUser> channels = sysUserMapper.getUserNames(deptIds);
            String channel[] = new String[channels.size()];

            for(int i=0; i<channels.size();i++){
                channel[i]=channels.get(i).getUsername();
            }

            criteria.and("channel").in(channel);
        }

        if(orderEntity.getPid()!=null){
            criteria.and("pid").is(orderEntity.getPid());
        }

        if (orderEntity.getTransaction_id()!=null){
            criteria.and("transaction_id").is(orderEntity.getTransaction_id());
        }

        if (orderEntity.getQTime()!=null){
            criteria.andOperator(Criteria.where("time_end").gte(orderEntity.getQTime().get(0).getTime()/1000).lte(orderEntity.getQTime().get(1).getTime()/1000));
        }else{
            criteria.andOperator(Criteria.where("time_end").gte(DateUtil.getDayBegin().getTime()/1000).lte(DateUtil.getDayEnd().getTime()/1000));
        }

        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.lookup("user","pid","id","orderUser"),
                Aggregation.sort(Sort.Direction.DESC,new String[]{"time_end"}),
                new SkipOperation((pageable.getPageNumber())*pageable.getPageSize()),
                Aggregation.limit(pageable.getPageSize())
        );
        AggregationResults<OrderEntity> ar = mongoTemplate.aggregate(aggregation, "order", OrderEntity.class);
        List<OrderEntity> list = ar.getMappedResults();

        aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group().count().as("total")
        );
        ar = mongoTemplate.aggregate(aggregation, "order", OrderEntity.class);
        long total = 0;
        if( ar.getMappedResults().size()>0){
            total= ar.getMappedResults().get(0).getTotal();
        }

        Map map =new HashMap();
        map.put("list",list);
        map.put("total",total);
        return map;
    }

    @Autowired
    private ChannelDataMapper channelDataMapper;

        @Override
        public List<ChannelData> selectChannelDataTree(  Integer time, String channel){
            QueryWrapper<ChannelData> wrapper =new QueryWrapper<>();
            if(time!=null&&time>0){
                wrapper.eq("day",time);
                wrapper.eq("channel",channel);
            }
            wrapper.orderBy(true,false,"id");
            List<ChannelData> list = channelDataMapper.selectList(wrapper);
            System.out.println(list);
            if(list.size()>0){
                for (ChannelData channelData:list){
                   Object[] retention= Arrays.stream(channelData.getRetentions().split(",")).toArray();
                   int[] ints=new int[retention.length];
                    for (int i=0;i<retention.length;i++){
                        ints[i]=Integer.parseInt(retention[i].toString()) ;

                    }
                    channelData.setRetention(ints);
                }
            }
            return list;
        }

    @Override
    public Map channelRechargeCount(ChannelDataEntity channelDataEntity, Pageable pageable) {
        Criteria criteria = new Criteria();
        Query query = new Query();
        int flag=0;
        if(!CollectionUtils.isEmpty(channelDataEntity.getDeptIds())){
           List<Long> deptIds= new ArrayList<>(channelDataEntity.getDeptIds());
           List<SysUser> channels = sysUserMapper.getUserNames(deptIds);
           String channel[] = new String[channels.size()];
           for(int i=0; i<channels.size();i++){
               channel[i]=channels.get(i).getUsername();
               if(channels.get(i).getUsername().indexOf("cl_")>0){
                   flag=1;
               }
           }
            criteria.and("channel").in(channel);
        }else {
            flag=1;
        }
        criteria.norOperator(Criteria.where("channel").regex("uid_"));
        if (channelDataEntity.getQTime()!=null){
            criteria.andOperator(Criteria.where("day").gte(channelDataEntity.getQTime().get(0).getTime()/1000).lte(channelDataEntity.getQTime().get(1).getTime()/1000));
        }

        if(channelDataEntity.getBeginTime()!=null&&channelDataEntity.getEndTime()!=null){
            criteria.andOperator(Criteria.where("day").gte(channelDataEntity.getBeginTime().getTime()/1000).lte(channelDataEntity.getEndTime().getTime()/1000));
        }else  if(channelDataEntity.getBeginTime()!=null){
            criteria.and("day").gte(channelDataEntity.getBeginTime().getTime()/1000);
        }else if(channelDataEntity.getEndTime()!=null){
            criteria.and("day").lte(channelDataEntity.getEndTime().getTime()/1000);
        }
        query.addCriteria(criteria);
        query.skip(pageable.getPageNumber()*pageable.getPageSize());
        query.limit(pageable.getPageSize());
        query.with( Sort.by(Sort.Direction.DESC,new String[]{"day"}));
        List<ChannelDataEntity> list =mongoTemplate.find(query, ChannelDataEntity.class);
        if(flag==1){
            List<ChannelDataEntity> list1 =fiveMongoTemplate.find(query, ChannelDataEntity.class);
            list.addAll(list1);
        }
        for(ChannelDataEntity ChannelDataEntity:list){
            List<ChannelDataEntity> list3 = mongoTemplate.find(new Query().addCriteria(new Criteria().and("day").is(ChannelDataEntity.getDay()).and("channel").is(ChannelDataEntity.getChannel())), ChannelDataEntity.class);
            if(flag==1){
                List<ChannelDataEntity> list1 =fiveMongoTemplate.find(new Query().addCriteria(new Criteria().and("day").is(ChannelDataEntity.getDay()).and("channel").is(ChannelDataEntity.getChannel())), ChannelDataEntity.class);
                list3.addAll(list1);
            }
            if(list3.size()==1){
                ChannelDataEntity.setRetention(list3.get(0).getRetention());
            }

            if(list3.size()>0){
                int[] retention=new int[31];
                for(ChannelDataEntity ChannelDataEntity3:list3){
                    int[] retention1=ChannelDataEntity3.getRetention();
                    for(int i=0;i<retention1.length;i++){
                        retention[i]=retention[i]+retention1[i];
                    }
                }
                ChannelDataEntity.setRetention(retention);
            }

        }

        Aggregation  aggregation = Aggregation.newAggregation(
                match(criteria),
                Aggregation.group("day","channel"),
                Aggregation.group().count().as("total")
        );
        AggregationResults<ChannelDataEntity> ar = mongoTemplate.aggregate(aggregation, "channel_data", ChannelDataEntity.class);
        long total=0;
        if(ar.getMappedResults().size()>0){
            total = ar.getMappedResults().get(0).getTotal();
        }
        if(flag==1){
            ar = fiveMongoTemplate.aggregate(aggregation, "channel_data", ChannelDataEntity.class);
            if(ar.getMappedResults().size()>0){
                total += ar.getMappedResults().get(0).getTotal();
            }
        }

        //累计
        Aggregation aggregation1 = Aggregation.newAggregation(match(criteria),Aggregation.group().sum("reg_num").as("reg_num").sum("charge_amount").as("charge_amount").sum("charge_pnum").as("charge_pnum").sum("new_charge_pnum").as("new_charge_pnum").sum("new_charge_amount").as("new_charge_amount").sum("first_charge_pnum").as("first_charge_pnum"));
        AggregationResults<ChannelDataEntity> ar1 = mongoTemplate.aggregate(aggregation1, "channel_data", ChannelDataEntity.class);
        List<ChannelDataEntity> list1 = ar1.getMappedResults();
        if(flag==1){
            ar1 = fiveMongoTemplate.aggregate(aggregation1, "channel_data", ChannelDataEntity.class);
            List<ChannelDataEntity> list4 = ar1.getMappedResults();
            if(list4.size()>0){
                if(list1.size()>0){
                list1.get(0).setCharge_amount(list4.get(0).getCharge_amount());
                list1.get(0).setCharge_pnum(list4.get(0).getCharge_pnum());
                list1.get(0).setNew_charge_amount(list4.get(0).getNew_charge_amount());
                list1.get(0).setNew_charge_pnum(list4.get(0).getNew_charge_pnum());
                list1.get(0).setReg_num(list4.get(0).getReg_num());
                }else {
                    list1 = list4;
                }
            }
        }

        //前10分钟
        criteria = new Criteria();
        if(!CollectionUtils.isEmpty(channelDataEntity.getDeptIds())){
            List<Long> deptIds= new ArrayList<>(channelDataEntity.getDeptIds());
            List<SysUser> channels = sysUserMapper.getUserNames(deptIds);
            String channel[] = new String[channels.size()];

            for(int i=0; i<channels.size();i++){
                channel[i]=channels.get(i).getUsername();
            }

            criteria.and("channel").in(channel);
        }

        long time =(new Date().getTime())/1000;
        long time1 =time-10*60;
        long time2 =time-20*60;
        long time3=time-30*60;
        long time4 =time-40*60;
        criteria.and("reg_time").gte(time1).lte(time);
        long reg_num1 =mongoTemplate.count(new Query().addCriteria(criteria), UserEntity.class);
        //前20分钟
        criteria = new Criteria();
        if(!CollectionUtils.isEmpty(channelDataEntity.getDeptIds())){
            List<Long> deptIds= new ArrayList<>(channelDataEntity.getDeptIds());
            List<SysUser> channels = sysUserMapper.getUserNames(deptIds);
            String channel[] = new String[channels.size()];

            for(int i=0; i<channels.size();i++){
                channel[i]=channels.get(i).getUsername();
            }

            criteria.and("channel").in(channel);
        }

        criteria.and("reg_time").gte(time2).lte(time);
        long reg_num2 =mongoTemplate.count(new Query().addCriteria(criteria), UserEntity.class);
        //前30分钟
        criteria = new Criteria();
        if(!CollectionUtils.isEmpty(channelDataEntity.getDeptIds())){
            List<Long> deptIds= new ArrayList<>(channelDataEntity.getDeptIds());
            List<SysUser> channels = sysUserMapper.getUserNames(deptIds);
            String channel[] = new String[channels.size()];

            for(int i=0; i<channels.size();i++){
                channel[i]=channels.get(i).getUsername();
            }

            criteria.and("channel").in(channel);
        }
        criteria.and("reg_time").gte(time3).lte(time);
        long reg_num3 =mongoTemplate.count(new Query().addCriteria(criteria), UserEntity.class);
        //前40分钟
        criteria = new Criteria();
        if(!CollectionUtils.isEmpty(channelDataEntity.getDeptIds())){
            List<Long> deptIds= new ArrayList<>(channelDataEntity.getDeptIds());
            List<SysUser> channels = sysUserMapper.getUserNames(deptIds);
            String channel[] = new String[channels.size()];

            for(int i=0; i<channels.size();i++){
                channel[i]=channels.get(i).getUsername();
            }

            criteria.and("channel").in(channel);
        }
        criteria.and("reg_time").gte(time4).lte(time);
        long reg_num4 =mongoTemplate.count(new Query().addCriteria(criteria), UserEntity.class);

        if (list1.size()>0){
            list1.get(0).setReg_num1((int) reg_num1);
            list1.get(0).setReg_num2((int) reg_num2);
            list1.get(0).setReg_num3((int) reg_num3);
            list1.get(0).setReg_num4((int) reg_num4);
        }

        Map map =new HashMap();
        map.put("content",list);
        map.put("totalElements",total);
        map.put("countData",list1);
        return map;
    }

    @Override
    public Map channelLtv(ChannelLtv channelLtv, Pageable pageable) {
        Page<ChannelLtv> page = new Page<>(pageable.getPageNumber()+1,pageable.getPageSize());
        QueryWrapper<ChannelLtv> wrapper =new QueryWrapper<>();
        if(channelLtv.getQTime()!=null){
            wrapper.ge("time",channelLtv.getQTime().get(0).getTime()/1000).le("time",channelLtv.getQTime().get(1).getTime()/1000);
        }

        if(!CollectionUtils.isEmpty(channelLtv.getDeptIds())){
            List<Long> deptIds= new ArrayList<>(channelLtv.getDeptIds());
            List<SysUser> channels = sysUserMapper.getUserNames(deptIds);
            String channel[] = new String[channels.size()];

            for(int i=0; i<channels.size();i++){
                channel[i]=channels.get(i).getUsername();
            }
            wrapper.in("channel",channel);
        }

        wrapper.orderByDesc("time").orderByDesc("total_charge");
        IPage<ChannelLtv> ipage = channelLtvMapper.selectPage(page,wrapper);
        List<ChannelLtv> list = ipage.getRecords();
        long total = ipage.getTotal();
        Map map =new HashMap();
        map.put("list",list);
        map.put("total",total);
        return map;
    }

    @Override
    public Map ioschannel(IosCdEntity iosCdEntity, Pageable pageable) {
        Query query = new Query();
        query.skip((pageable.getPageNumber())*pageable.getPageSize());
        query.limit(pageable.getPageSize());
        Criteria criteria = new Criteria();
        if (iosCdEntity.getQTime()!=null){
            criteria.andOperator(Criteria.where("time").gte(iosCdEntity.getQTime().get(0).getTime()/1000).lte(iosCdEntity.getQTime().get(1).getTime()/1000));
        }
        query.addCriteria(criteria);
        query.with( Sort.by(Sort.Direction.DESC,new String[]{"time"}));
        List<IosCdEntity> list = mongoTemplate.find(query, IosCdEntity.class);
        for(IosCdEntity iosCdEntity1:list){
            Map<String , Object> channelsMap =iosCdEntity1.getChannels();
            double channelValue = 0;
            for (Object channelValue1 : channelsMap.values()) {
                String channelValueS=channelValue1.toString();
                channelValue=channelValue+Double.valueOf(channelValueS);
            }
            iosCdEntity1.setChannelsValue(channelValue);
        }
        long total = mongoTemplate.count(query, IosCdEntity.class);

        Map map =new HashMap();
        map.put("content",list);
        map.put("totalElements",total);
        return map;
    }

    @Override
    public Map channelIdData(ChannelIdData channelIdData, Pageable pageable) {
        Page<ChannelIdData> page = new Page<>(pageable.getPageNumber()+1,pageable.getPageSize());

        QueryWrapper<ChannelIdData> wrapper =new QueryWrapper<>();

        if(channelIdData.getQTime()!=null){
            wrapper.ge("time",channelIdData.getQTime().get(0).getTime()/1000);
            wrapper.le("time",channelIdData.getQTime().get(1).getTime()/1000);
        }

        if(channelIdData.getChannelId()!=null){
            wrapper.ge("channel",channelIdData.getChannel());
        }
        wrapper.orderByDesc("time");
        IPage<ChannelIdData> ipage = channelIdDataMapper.selectPage(page,wrapper);
        List<ChannelIdData> list = ipage.getRecords();
        long total = ipage.getTotal();
        Map map =new HashMap();

        List<ChannelIdData> list1=new ArrayList<>();
        if(list1.size()>0) {
            for (ChannelIdData channelIdData1 : list) {
                list1.get(0).setActiveNum(channelIdData1.getActiveNum());
                list1.get(0).setRechargeNum(channelIdData1.getRechargeNum());
                list1.get(0).setRechargePerson(channelIdData1.getRechargePerson());
                list1.get(0).setRegNum(channelIdData1.getRegNum());
            }
        }


        map.put("content",list);
        map.put("totalElements",total);
        map.put("countData",list1);
        return map;
    }

}
